/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package we.dispatcher;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import we.config.CConstant;
import we.dispatcher.writer.IWritingProcessor;
import we.exception.UnsupportedTypeException;
import we.exception.WritingPacketException;

/**
 *
 * @author trungdv2
 */
public class CPacketWriter
{

    public void PutID(int id)
    {
        buffer.clear();
        buffer.putInt(-1);
        buffer.putInt(id);
    }

    public void PutDouble(double data)
    {
        buffer.putDouble(data);
    }

    public static class WriterPair
    {

        public IWritingProcessor processor;
        public Object obj;

        public WriterPair(IWritingProcessor processor, Object obj)
        {
            this.processor = processor;
            this.obj = obj;
        }
    }
    final static Charset charset = Charset.forName("UTF-8");
    ByteBuffer buffer;

    public CPacketWriter()
    {
        this(CConstant.MAX_MESSAGE_LENGTH, false);
    }   
    

    public CPacketWriter(int maxLength)
    {
        this(maxLength, false);
    }

    public CPacketWriter(int maxLength, boolean direct)
    {
        if (direct)
        {
            buffer = ByteBuffer.allocateDirect(maxLength);
        } else
        {
            buffer = ByteBuffer.allocate(maxLength);
        }
        buffer.order(ByteOrder.LITTLE_ENDIAN);
    }

    public ByteBuffer buffer()
    {
        return buffer;
    }

    public void PutString(String s)
    {
        byte[] arr = s.getBytes(charset);
        buffer.putShort((short) arr.length);
        buffer.put(arr);
    }

    public void PutString(String s, int maxLength)
    {
        byte[] arr = s.getBytes(charset);
        buffer.put(arr);
        for (int i = arr.length; i < maxLength; i++)
        {
            buffer.put((byte) 0);
        }
    }

    public void writeByProcessor(int id, WriterPair... pairs)
    {
        buffer.clear();
        buffer.putInt(-1);
        buffer.putInt(id);

        for (int i = 0; i < pairs.length; i++)
        {
            WriterPair tmp = pairs[i];
            tmp.processor.write(this, tmp.obj);
        }

        buffer.putInt(0, buffer.position());
        buffer.flip();
    }

    public void writeByProcessor(int id, IWritingProcessor[] processors, Object... objs) throws WritingPacketException
    {
        if (processors.length != objs.length)
        {
            throw new WritingPacketException("Độ dài của processors và objs khác nhau. Lần lượt là : " + processors.length + ", " + objs.length);
        }

        buffer.clear();
        buffer.putInt(-1);
        buffer.putInt(id);

        for (int i = 0; i < processors.length; i++)
        {
            processors[i].write(this, objs[i]);
        }

        buffer.putInt(0, buffer.position());
        buffer.flip();
    }

    public void write(int id, Object... params) throws UnsupportedTypeException
    {
        buffer.clear();
        buffer.putInt(-1);
        buffer.putInt(id);
        
        for (int i = 0; i < params.length; i++)
        {
            Class<?> _class = params[i].getClass();
            if (_class == String.class)
            {
                PutString((String) params[i]);
            } else if (_class == Byte.class)
            {
                buffer.put((Byte) params[i]);
            } else if (_class == Integer.class)
            {
                buffer.putInt((Integer) params[i]);
            } else if (_class == Long.class)
            {
                buffer.putLong((Long) params[i]);
            } else if (_class == Short.class)
            {
                buffer.putShort((Short) params[i]);
            } else
            {
                throw new UnsupportedTypeException("Chưa hỗ trợ ghi object kiểu : " + _class.getName(), new Throwable());
            }
        }
        buffer.putInt(0, buffer.position());
        buffer.flip();
    }

    public void PutByte(byte b)
    {
        buffer.put(b);
    }

    public void PutInt(int data)
    {
        buffer.putInt(data);
    }

    

    public void PutFloat(float data)
    {
        buffer.putDouble(data);
    }

    public void PutLengthAndFlip()
    {
        buffer.putInt(0, buffer.position());
        buffer.flip();
    }
}
